package com.xinyin.aiqinhaiback.modbus;

import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.xinyin.aiqinhaiback.Utils.PortGroupingUtil;
import com.xinyin.aiqinhaiback.common.ConfigCache;
import com.xinyin.aiqinhaiback.common.Enum.ResultEnum;
import com.xinyin.aiqinhaiback.config.ModbusConfig;
import com.xinyin.aiqinhaiback.exception.MyException;
import com.xinyin.aiqinhaiback.model.entity.Information;
import com.xinyin.aiqinhaiback.model.entity.ModBusDevice;
import com.xinyin.aiqinhaiback.model.entity.SensorInfo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

@Component
public class ModbusUtil {

    private static ModbusPoolManager manager;
    private static ModbusConfig modbusConfig;
    @Autowired
    private ModbusConfig modbusConfigBean;
    @Autowired
    private ModbusPoolManager managerBean;

    @PostConstruct
    public void init() {
        this.manager = managerBean;
        this.modbusConfig = modbusConfigBean;
    }


    public static synchronized ModBusDevice getData() throws Exception {
        List<String> ipKeys = Arrays.asList("cold", "heat", "coolingTower", "fan1_1", "fan1_2", "fan1_3", "fan1_4", "fan1_5", "fan2_1", "fan2_2", "fan2_3", "fan2_4", "fan3_1", "fan3_2", "fan3_3", "fan3_4", "fan4_1", "fan4_2", "fan4_3");
        Map<String, AtomicReference<BatchResults<Integer>>> dataMap = new ConcurrentHashMap<>();
        List<ModbusMaster> masters = new ArrayList<>();
        List<ModbusClient> clients = new ArrayList<>();
        CountDownLatch latch = new CountDownLatch(ipKeys.size());

        for (String ipKey : ipKeys) {
            dataMap.put(ipKey, new AtomicReference<>());
            ModbusMaster master = manager.getMaster(ipKey);
            masters.add(master);
            clients.add(new ModbusClient(master));
        }

        List<SensorInfo> sensorInfos = ConfigCache.data.get("sensors");
        List<Information> informationList = ConfigCache.data.get("devices");

        List<String> portList = new ArrayList<>();
        sensorInfos.forEach(item -> portList.add(item.getAddress() + ":" + item.getModbus()));
        informationList.forEach(item -> portList.add(item.getAddress() + ":" + item.getModbus()));

        Map<String, Set<Integer>> map = PortGroupingUtil.groupPortsByIp(portList);
        System.out.println("ip端口分组" + map);

        for (String ipKey : ipKeys) {
            String ip = modbusConfig.getIp(ipKey);
            Set<Integer> ports = map.get(ip);
            if (ports != null) {
                new Thread(() -> {
                    try {
                        dataMap.get(ipKey).set(clients.get(ipKeys.indexOf(ipKey)).batchRead(ports));
                    } catch (Exception e) {
                        System.out.println(ip + "链接异常" + e.getMessage());
                    } finally {
                        manager.returnMaster(ipKey, masters.get(ipKeys.indexOf(ipKey)));
                        latch.countDown();
                    }
                }).start();
            } else {
                manager.returnMaster(ipKey, masters.get(ipKeys.indexOf(ipKey)));
                latch.countDown();
            }
        }

        latch.await(); // 等待所有线程完成

        for (String ipKey : ipKeys) {
            BatchResults<Integer> batchResults = dataMap.get(ipKey).get();
            System.out.println(ipKey + "Data:" + batchResults);

            sensorInfos.forEach(item -> {
                try {
                    updateSensorInfo(item, batchResults, modbusConfig.getIp(ipKey));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                if (item.getValue() == null) {
                    savaLog(item.getSensorParamName());
                }
            });

            informationList.forEach(item -> {
                try {
                    updateInformations(item, batchResults, modbusConfig.getIp(ipKey));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                if (item.getValue() == null) {
                    savaLog(item.getInformationName());
                }
            });
        }

        ModBusDevice modBusDevice = new ModBusDevice();
        modBusDevice.setInformationList(informationList);
        modBusDevice.setSensorInfoList(sensorInfos);
        return modBusDevice;
    }


    public static synchronized ModBusDevice getInformationData(List<Information> informationList) throws Exception {
        // 创建一个AtomicReference数组，用于存储每个设备的批量读取结果
        AtomicReference<BatchResults<Integer>>[] dataRefs = new AtomicReference[19];
        // 设备名称数组
        String[] deviceNames = {
                "heat", "cold", "coolingTower",
                "fan1_1", "fan1_2", "fan1_3", "fan1_4", "fan1_5",
                "fan2_1", "fan2_2", "fan2_3", "fan2_4",
                "fan3_1", "fan3_2", "fan3_3", "fan3_4",
                "fan4_1", "fan4_2", "fan4_3"
        };

        // 初始化数据引用数组
        for (int i = 0; i < dataRefs.length; i++) {
            dataRefs[i] = new AtomicReference<>();
        }

        // 提取端口列表
        List<String> portList = new ArrayList<>();
        informationList.forEach(item -> portList.add(item.getAddress() + ":" + item.getModbus()));

        // 根据IP对端口进行分组
        Map<String, Set<Integer>> portMap = PortGroupingUtil.groupPortsByIp(portList);

        // 初始化Modbus主机和客户端
        Map<String, ModbusMaster> masters = new HashMap<>();
        Map<String, ModbusClient> clients = new HashMap<>();
        for (String deviceName : deviceNames) {
            ModbusMaster master = manager.getMaster(deviceName);
            masters.put(deviceName, master);
            clients.put(deviceName, new ModbusClient(master));
        }

        // 创建一个CountDownLatch，用于等待所有设备处理完成
        CountDownLatch latch = new CountDownLatch(deviceNames.length);

        // 并行处理每个设备
        for (int i = 0; i < deviceNames.length; i++) {
            String deviceName = deviceNames[i];
            ModbusClient client = clients.get(deviceName);
            Set<Integer> ports = portMap.get(modbusConfig.getIp(deviceName));
            AtomicReference<BatchResults<Integer>> dataRef = dataRefs[i];

            if (ports != null) {
                new Thread(() -> {
                    try {
                        dataRef.set(client.batchRead(ports));
                    } catch (Exception e) {
                        // 捕获异常并打印错误信息
                        System.out.println(modbusConfig.getIp(deviceName) + " 读取失败: " + e.getMessage());
                    } finally {
                        // 归还主机资源
                        manager.returnMaster(deviceName, masters.get(deviceName));
                        latch.countDown();
                    }
                }).start();
            } else {
                // 如果没有端口，直接归还主机资源
                manager.returnMaster(deviceName, masters.get(deviceName));
                latch.countDown();
            }
        }

        try {
            // 等待所有线程完成
            latch.await();
        } catch (InterruptedException e) {
            // 捕获线程中断异常
            Thread.currentThread().interrupt();
            throw new MyException(ResultEnum.COMMON_FAILED); // 自定义异常信息
        }

        // 更新信息列表
        for (Information item : informationList) {
            try {
                updateInformations(item, dataRefs[0].get(), modbusConfig.getIp("heat"));
                updateInformations(item, dataRefs[1].get(), modbusConfig.getIp("cold"));
                updateInformations(item, dataRefs[2].get(), modbusConfig.getIp("coolingTower"));
            } catch (NoSuchFieldException | IllegalAccessException e) {
                // 捕获字段不存在或访问权限异常
                e.printStackTrace();
            }
            if (item.getValue() == null) {
                // 如果值为空，记录日志
                savaLog(item.getInformationName());
            }
        }

        // 创建并返回ModBusDevice对象
        ModBusDevice modBusDevice = new ModBusDevice();
        modBusDevice.setInformationList(informationList);
        return modBusDevice;
    }

    private static synchronized void savaLog(String name) {
        //informationMapper.addLog(name);
    }

    ;

    // 更新 SensorInfo 的辅助方法
    private static synchronized void updateSensorInfo(SensorInfo item, BatchResults<Integer> data, String targetIp) throws NoSuchFieldException, IllegalAccessException {
        if (data == null) {
            return;
        }
        Map<Integer, Object> res = changeData(data);
        if (data != null && item.getAddress().equals(targetIp)) {
            if (res.get(item.getModbus()) != null) {
                try {
                    DecimalFormat df = new DecimalFormat("0.00");
                    String formatted = df.format(res.get(item.getModbus())); // 结果："3.14"
                    item.setValue(formatted);
                } catch (Exception e) {
                    item.setValue(res.get(item.getModbus()).toString().contains("E") == true ? 0.0 : res.get(item.getModbus()));
                }
            } else {
                item.setValue(-1);
            }
        }
    }

    // 更新 Informations 的辅助方法
    private static synchronized void updateInformations(Information item, BatchResults<Integer> data, String targetIp) throws NoSuchFieldException, IllegalAccessException {
        if (data == null) {
            return;
        }
        Map<Integer, Object> res = changeData(data);
        if (data != null && item.getAddress().equals(targetIp)) {
            if (res.get(item.getModbus()) != null) {
                try {
                    DecimalFormat df = new DecimalFormat("0.00");
                    String formatted = df.format(res.get(item.getModbus())); // 结果："3.14"
                    item.setValue(formatted);
                } catch (Exception e) {
                    item.setValue(res.get(item.getModbus()).toString().contains("E") == true ? 0.0 : res.get(item.getModbus()));
                }
            } else {
                item.setValue(-1);
            }

        }
    }

    synchronized private static Map<Integer, Object> changeData(BatchResults<Integer> results) throws NoSuchFieldException, IllegalAccessException {
        //System.out.println("数据集change"+results);
        Class<? extends BatchResults> resultClass = results.getClass();

        Field resultData = resultClass.getDeclaredField("data");
        resultData.setAccessible(true);
        Map<Integer, Object> resultRealData = (Map<Integer, Object>) resultData.get(results);
        return resultRealData;
    }

}
